﻿namespace CSharpCompiler
{
    using System;
    using System.CodeDom.Compiler;
    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    public class ScriptBundleLoader
    {
        [CompilerGenerated]
        private static Func<Type, object> <>f__am$cache6;
        [CompilerGenerated]
        private static Action<object> <>f__am$cache7;
        private List<ScriptBundle> allFilesBundle;
        public Func<Type, object> createInstance;
        public Action<object> destroyInstance;
        public TextWriter errorWriter;
        public TextWriter logWriter;
        private ISynchronizeInvoke synchronizedInvoke;

        public ScriptBundleLoader(ISynchronizeInvoke synchronizedInvoke)
        {
            if (<>f__am$cache6 == null)
            {
                <>f__am$cache6 = new Func<Type, object>(ScriptBundleLoader.<createInstance>m__198);
            }
            this.createInstance = <>f__am$cache6;
            if (<>f__am$cache7 == null)
            {
                <>f__am$cache7 = new Action<object>(ScriptBundleLoader.<destroyInstance>m__199);
            }
            this.destroyInstance = <>f__am$cache7;
            this.logWriter = Console.Out;
            this.errorWriter = Console.Out;
            this.allFilesBundle = new List<ScriptBundle>();
            this.synchronizedInvoke = synchronizedInvoke;
        }

        [CompilerGenerated]
        private static object <createInstance>m__198(Type type)
        {
            return Activator.CreateInstance(type);
        }

        [CompilerGenerated]
        private static void <destroyInstance>m__199(object)
        {
        }

        public ScriptBundle LoadAndWatchScriptsBundle(IEnumerable<string> fileSources)
        {
            ScriptBundle item = new ScriptBundle(this, fileSources);
            this.allFilesBundle.Add(item);
            return item;
        }

        public class ScriptBundle
        {
            [CompilerGenerated]
            private static Func<string, string> <>f__am$cache6;
            [CompilerGenerated]
            private static Func<Assembly, string> <>f__am$cache7;
            [CompilerGenerated]
            private static Func<string, bool> <>f__am$cache8;
            private string[] assemblyReferences;
            private IEnumerable<string> filePaths;
            private List<FileSystemWatcher> fileSystemWatchers = new List<FileSystemWatcher>();
            private List<object> instances = new List<object>();
            private ScriptBundleLoader manager;

            public ScriptBundle(ScriptBundleLoader manager, IEnumerable<string> filePaths)
            {
                if (<>f__am$cache6 == null)
                {
                    <>f__am$cache6 = new Func<string, string>(ScriptBundleLoader.ScriptBundle.<ScriptBundle>m__19A);
                }
                this.filePaths = filePaths.Select<string, string>(<>f__am$cache6);
                this.manager = manager;
                AppDomain currentDomain = AppDomain.CurrentDomain;
                if (<>f__am$cache7 == null)
                {
                    <>f__am$cache7 = new Func<Assembly, string>(ScriptBundleLoader.ScriptBundle.<ScriptBundle>m__19B);
                }
                this.assemblyReferences = currentDomain.GetAssemblies().Select<Assembly, string>(<>f__am$cache7).ToArray<string>();
                manager.logWriter.WriteLine("loading " + string.Join(", ", filePaths.ToArray<string>()));
                this.CompileFiles();
                this.CreateFileWatchers();
                this.CreateNewInstances();
            }

            [CompilerGenerated]
            private static string <ScriptBundle>m__19A(string x)
            {
                return Path.GetFullPath(x);
            }

            [CompilerGenerated]
            private static string <ScriptBundle>m__19B(Assembly a)
            {
                return a.Location;
            }

            private void CompileFiles()
            {
                if (<>f__am$cache8 == null)
                {
                    <>f__am$cache8 = x => File.Exists(x);
                }
                this.filePaths = this.filePaths.Where<string>(<>f__am$cache8).ToArray<string>();
                CompilerParameters options = new CompilerParameters {
                    GenerateExecutable = false,
                    GenerateInMemory = true
                };
                options.ReferencedAssemblies.AddRange(this.assemblyReferences);
                CompilerResults results = new CSharpCompiler.CodeCompiler().CompileAssemblyFromFileBatch(options, this.filePaths.ToArray<string>());
                IEnumerator enumerator = results.Errors.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        object current = enumerator.Current;
                        this.manager.errorWriter.WriteLine(current);
                    }
                }
                finally
                {
                    IDisposable disposable = enumerator as IDisposable;
                    if (disposable == null)
                    {
                    }
                    disposable.Dispose();
                }
                this.assembly = results.CompiledAssembly;
            }

            private void CreateFileWatchers()
            {
                IEnumerator<string> enumerator = this.filePaths.GetEnumerator();
                try
                {
                    while (enumerator.MoveNext())
                    {
                        string current = enumerator.Current;
                        FileSystemWatcher item = new FileSystemWatcher();
                        this.fileSystemWatchers.Add(item);
                        item.Path = Path.GetDirectoryName(current);
                        item.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.DirectoryName | NotifyFilters.FileName;
                        item.Filter = Path.GetFileName(current);
                        item.Changed += (o, a) => this.Reload(false);
                        item.Deleted += (o, a) => this.Reload(false);
                        item.Renamed += delegate (object o, RenamedEventArgs a) {
                            <CreateFileWatchers>c__AnonStorey90 storey = new <CreateFileWatchers>c__AnonStorey90 {
                                a = a,
                                <>f__this = this
                            };
                            this.filePaths = this.filePaths.Select<string, string>(new Func<string, string>(storey.<>m__1A2));
                            this.Reload(true);
                        };
                        item.SynchronizingObject = this.manager.synchronizedInvoke;
                        item.EnableRaisingEvents = true;
                    }
                }
                finally
                {
                    if (enumerator == null)
                    {
                    }
                    enumerator.Dispose();
                }
            }

            private void CreateNewInstances()
            {
                if (this.assembly != null)
                {
                    <CreateNewInstances>c__AnonStorey91 storey = new <CreateNewInstances>c__AnonStorey91 {
                        <>f__this = this
                    };
                    Type[] types = this.assembly.GetTypes();
                    for (int i = 0; i < types.Length; i++)
                    {
                        storey.type = types[i];
                        this.manager.synchronizedInvoke.Invoke(new Action(storey.<>m__1A0), null);
                    }
                }
            }

            private void Reload(bool recreateWatchers = false)
            {
                this.manager.logWriter.WriteLine("reloading " + string.Join(", ", this.filePaths.ToArray<string>()));
                this.StopInstances();
                this.CompileFiles();
                this.CreateNewInstances();
                if (recreateWatchers)
                {
                    this.StopFileWatchers();
                    this.CreateFileWatchers();
                }
            }

            private void StopFileWatchers()
            {
                foreach (FileSystemWatcher watcher in this.fileSystemWatchers)
                {
                    watcher.EnableRaisingEvents = false;
                    watcher.Dispose();
                }
                this.fileSystemWatchers.Clear();
            }

            private void StopInstances()
            {
                <StopInstances>c__AnonStorey92 storey = new <StopInstances>c__AnonStorey92 {
                    <>f__this = this
                };
                using (List<object>.Enumerator enumerator = this.instances.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        storey.instance = enumerator.Current;
                        this.manager.synchronizedInvoke.Invoke(new Action(storey.<>m__1A1), null);
                    }
                }
                this.instances.Clear();
            }

            public Assembly assembly { get; private set; }

            [CompilerGenerated]
            private sealed class <CreateFileWatchers>c__AnonStorey90
            {
                internal ScriptBundleLoader.ScriptBundle <>f__this;
                internal RenamedEventArgs a;

                internal string <>m__1A2(string x)
                {
                    if (x == this.a.OldFullPath)
                    {
                        return this.a.FullPath;
                    }
                    return x;
                }
            }

            [CompilerGenerated]
            private sealed class <CreateNewInstances>c__AnonStorey91
            {
                internal ScriptBundleLoader.ScriptBundle <>f__this;
                internal Type type;

                internal void <>m__1A0()
                {
                    this.<>f__this.instances.Add(this.<>f__this.manager.createInstance(this.type));
                }
            }

            [CompilerGenerated]
            private sealed class <StopInstances>c__AnonStorey92
            {
                internal ScriptBundleLoader.ScriptBundle <>f__this;
                internal object instance;

                internal void <>m__1A1()
                {
                    this.<>f__this.manager.destroyInstance(this.instance);
                }
            }
        }
    }
}

